/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package com.mahumLogs.beans;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.librairies.exceptions.CommandFailException;
import com.mahumLogs.utils.SSH;
import com.mahumLogs.utils.SSHStatus;
import java.io.Serializable;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import org.primefaces.context.RequestContext;

/**
 *
 * @author Kalast
 */

@Named
@SessionScoped
public class ClientSSHBean implements Serializable{

    @Inject
    private ConfigurationBean configBean;
    
    private String dhcpIP = "";
    private String dhcpUser = "";
    private String dhcpPwd = "";
    
    private String logsIP = "";
    private String logsUser = "";
    private String logsPwd = "";
    
    private String fwIP = "";
    private String fwUser = "";
    private String fwPwd = "";
    
    private Session sessionLogs;
    private Session sessionDHCP;
    private Session sessionFireWall;
    
    private SSHStatus statusLogs = SSHStatus.ERROR_CONNECTION;
    private SSHStatus statusDHCP = SSHStatus.ERROR_CONNECTION;
    private SSHStatus statusFW = SSHStatus.ERROR_CONNECTION;
    
    public ClientSSHBean() {
        
    }
    
    @PostConstruct
    public void init(){

    }
    
    public ChannelExec execOnDHCP(String cmd) throws CommandFailException{
        //this.reloadDHCPSession();
        if(this.sessionDHCP == null || !this.sessionDHCP.isConnected()){
            try {
                this.sessionDHCP = SSH.createSession(configBean.findByKey("DHCP_SERVER_IP").getValeur()
                        , configBean.findByKey("DHCP_SERVER_USER").getValeur()
                        , configBean.findByKey("DHCP_SERVER_PWD").getValeur());
            System.out.println("Session crée");
            } catch (JSchException ex) {
                Logger.getLogger(ClientSSHBean.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return exec(this.sessionDHCP, cmd);
    }
    
    public ChannelExec execOnFirewall(String cmd) throws CommandFailException{
        //this.reloadFireWallSession();
        if(this.sessionFireWall == null || !this.sessionFireWall.isConnected()){
            try {
                this.sessionFireWall = SSH.createSession(configBean.findByKey("FIREWALL_SERVER_IP").getValeur()
                        , configBean.findByKey("FIREWALL_SERVER_USER").getValeur()
                        , configBean.findByKey("FIREWALL_SERVER_PWD").getValeur());
                System.out.println("Session crée");
            } catch (JSchException ex) {
                Logger.getLogger(ClientSSHBean.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return exec(this.sessionFireWall, cmd);
    }
    
    public ChannelExec execOnLogs(String cmd) throws CommandFailException{
        //this.reloadLogsSession();
        if(this.sessionLogs == null || !this.sessionLogs.isConnected()){
            try {
                this.sessionLogs = SSH.createSession(configBean.findByKey("SQUID_SERVER_IP").getValeur()
                        , configBean.findByKey("SQUID_SERVER_USER").getValeur()
                        , configBean.findByKey("SQUID_SERVER_PWD").getValeur());
                System.out.println("Session crée");
            } catch (JSchException ex) {
                Logger.getLogger(ClientSSHBean.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return exec(this.sessionLogs, cmd);
    }
    
    public void reloadLogsSession(){
        if(this.statusLogs.getId() != SSHStatus.IN_WAIT.getId()){
            this.statusLogs = SSHStatus.IN_WAIT;
            final String ip = configBean.findByKey("SQUID_SERVER_IP").getValeur();
            final String user = configBean.findByKey("SQUID_SERVER_USER").getValeur();
            final String pwd = configBean.findByKey("SQUID_SERVER_PWD").getValeur();
            new Thread(new Runnable(){

                @Override
                public void run() {
                    if(LogsHasChanged(ip, user, pwd) || !sessionLogs.isConnected()){
                        try {
                            testCreateAllSession();
                        } catch (JSchException ex) {}
                        System.out.println("LOGS change or not connected");
                        logsIP = ip;
                        logsUser = user;
                        logsPwd = pwd;
                        boolean error = false;
                        //On test si le serveur LOGS est pareil que le serveur DHCP
                        if (logsIP.equals(dhcpIP) && logsUser.equals(dhcpUser)) {
                            sessionLogs = sessionDHCP;
                            if(!sessionDHCP.isConnected()){
                                try {
                                    sessionDHCP.connect();
                                } catch (JSchException ex) {
                                    error = true;
                                }
                            } 
                        //On test si le serveur LOGS est pareil que le serveur DHCP
                        } else if (logsIP.equals(fwIP) && logsUser.equals(fwUser)) {
                            sessionLogs = sessionFireWall;
                            if(!sessionFireWall.isConnected()){
                                try {
                                    sessionFireWall.connect();
                                } catch (JSchException ex) {
                                    error = true;
                                }
                            } 
                        } else {
                            try {
                                if(!sessionLogs.isConnected()){
                                    System.out.println("COnnexion a LOGS en coursd");
                                    sessionLogs.connect();
                                    System.out.println("COnnexion terminée");
                                }
                            } catch (JSchException ex) {
                                error = true;
                            }
                        }

                        if(error){
                            statusLogs = SSHStatus.ERROR_CONNECTION;
                        } else {
                            statusLogs = SSHStatus.CONNECTION_OK;
                        }
                    } else {
                        statusLogs = SSHStatus.CONNECTION_OK;
                    }
                }
                
            }).start();
        } else {
            this.sendWarningMessage("En cours", "Une opération est déjà en cours... Veuillez patienter.");
        }
    }
    
    public void reloadDHCPSession(){
        if(this.statusDHCP.getId() != SSHStatus.IN_WAIT.getId()){    
            statusDHCP = SSHStatus.IN_WAIT;
            final String ip = configBean.findByKey("DHCP_SERVER_IP").getValeur();
            final String user = configBean.findByKey("DHCP_SERVER_USER").getValeur();
            final String pwd = configBean.findByKey("DHCP_SERVER_PWD").getValeur();
            new Thread(new Runnable(){

                @Override
                public void run() {
                    if(DHCPHasChanged(ip, user, pwd) || !sessionDHCP.isConnected()){
                        try {
                            testCreateAllSession();
                        } catch (JSchException ex) {}

                        System.out.println("DHCP change or not connected");
                        dhcpIP = ip;
                        dhcpUser = user;
                        dhcpPwd = pwd;
                        boolean error = false;
                        //On test si le serveur LOGS est pareil que le serveur DHCP
                        if (dhcpIP.equals(logsIP) && dhcpUser.equals(logsUser)) {
                            sessionDHCP = sessionLogs;
                            if(!sessionLogs.isConnected()){
                                try {
                                    sessionLogs.connect();
                                } catch (JSchException ex) {
                                    error = true;
                                }
                            } 
                        //On test si le serveur LOGS est pareil que le serveur DHCP
                        } else if (dhcpIP.equals(fwIP) && dhcpUser.equals(fwUser)) {
                            sessionDHCP = sessionFireWall;
                            if(!sessionFireWall.isConnected()){
                                try {
                                    sessionFireWall.connect();
                                } catch (JSchException ex) {
                                    error = true;
                                }
                            } 
                        } else {
                            try {
                                if(!sessionDHCP.isConnected()){
                                    sessionDHCP.connect();
                                }
                            } catch (JSchException ex) {
                                error = true;
                            }
                        }

                        if(error){
                            statusDHCP = SSHStatus.ERROR_CONNECTION;
                        } else {
                            statusDHCP = SSHStatus.CONNECTION_OK;
                        }
                    } else {
                        statusDHCP = SSHStatus.CONNECTION_OK;
                    }
                }
            }).start();
            
        } else {
            this.sendWarningMessage("En cours", "Une opération est déjà en cours... Veuillez patienter.");
        }
    }
    
    public void reloadFireWallSession(){
        if(this.statusFW.getId() != SSHStatus.IN_WAIT.getId()){
            statusFW = SSHStatus.IN_WAIT;
            final String ip = configBean.findByKey("FIREWALL_SERVER_IP").getValeur();
            final String user = configBean.findByKey("FIREWALL_SERVER_USER").getValeur();
            final String pwd = configBean.findByKey("FIREWALL_SERVER_PWD").getValeur();
            
            new Thread(new Runnable(){

                @Override
                public void run() {
                    if(FireWallHasChanged(ip, user, pwd) || !sessionFireWall.isConnected()){
                        try {
                            testCreateAllSession();
                        } catch (JSchException ex) {}
                        System.out.println("FIREWALL change or not connected");
                        fwIP = ip;
                        fwUser = user;
                        fwPwd = pwd;
                        boolean error = false;
                        //On test si le serveur LOGS est pareil que le serveur FireWall
                        if (fwIP.equals(logsIP) && fwUser.equals(logsUser)) {
                            sessionFireWall = sessionLogs;
                            if(!sessionLogs.isConnected()){
                                try {
                                    sessionLogs = SSH.createSession(logsIP,logsUser,logsPwd);
                                    sessionLogs.connect();
                                } catch (JSchException ex) {
                                    error = true;
                                }
                            } 
                        //On test si le serveur FIREWALL est pareil que le serveur DHCP
                        } else if (fwIP.equals(dhcpIP) && fwUser.equals(dhcpUser)) {
                            sessionFireWall = sessionDHCP;
                            if(!sessionFireWall.isConnected()){
                                try {
                                    sessionFireWall.connect();
                                } catch (JSchException ex) {
                                    error = true;
                                }
                            } 
                        } else {
                            try {
                                if(!sessionFireWall.isConnected()){
                                    sessionFireWall.connect();
                                }
                            } catch (JSchException ex) {
                                error = true;
                            }
                        }

                        if(error){
                            sendErrorMessage("Problème de connexion", "Serveur " + sessionFireWall.getHost() + " indisponible.");
                            statusFW = SSHStatus.ERROR_CONNECTION;
                        } else {
                            statusFW = SSHStatus.CONNECTION_OK;
                        }
                    } else {
                        statusFW = SSHStatus.CONNECTION_OK;
                    }
                }
            }).start();
            
        } else {
            this.sendWarningMessage("En cours", "Une opération est déjà en cours... Veuillez patienter.");
        }
    }
    
    private void testCreateAllSession() throws JSchException{
        if(this.sessionDHCP == null){
            this.sessionDHCP = SSH.createSession(dhcpIP, dhcpUser, dhcpPwd);
        }
        
        if(this.sessionLogs == null){
            this.sessionLogs = SSH.createSession(logsIP, logsUser, logsPwd);
        }
        
        if(this.sessionFireWall == null){
            this.sessionFireWall = SSH.createSession(fwIP, fwUser, fwPwd);
        }
    }
    
    public void sendErrorMessage(String title, String content){
        FacesMessage statusMessage = new FacesMessage(title, content);
        statusMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
        sendMessage(statusMessage);
    }
    
    public void sendFatalMessage(String title, String content){
        FacesMessage statusMessage = new FacesMessage(title, content);
        statusMessage.setSeverity(FacesMessage.SEVERITY_FATAL);
        sendMessage(statusMessage);
    }
    
    public void sendWarningMessage(String title, String content){
        FacesMessage statusMessage = new FacesMessage(title, content);
        statusMessage.setSeverity(FacesMessage.SEVERITY_WARN);
        sendMessage(statusMessage);
    }
    
    public void sendInfoMessage(String title, String content){
        FacesMessage statusMessage = new FacesMessage(title, content);
        statusMessage.setSeverity(FacesMessage.SEVERITY_INFO);
        sendMessage(statusMessage);
    }
    
    private void sendMessage(FacesMessage statusMessage){
        if(FacesContext.getCurrentInstance() != null && RequestContext.getCurrentInstance() != null){
            List<FacesMessage> msgs = FacesContext.getCurrentInstance().getMessageList();
            boolean add = true;
            for(FacesMessage msg : msgs){
                if(msg.getDetail().equals(statusMessage.getDetail())
                        && msg.getSummary().equals(statusMessage.getSummary())){
                    add = false;
                }
            }

            if(add){
                FacesContext.getCurrentInstance().addMessage(null, statusMessage);
                RequestContext.getCurrentInstance().update("growl");
            }
        }
    }
    
    /** 
     * @param session
     * @param cmd
     * @return 
     */
    private ChannelExec exec(Session session, String cmd) throws CommandFailException{
        System.out.println("Tentative d'execution de la commande :" + cmd);
        ChannelExec channel = null;
        boolean error = false;
        if(!session.isConnected()){
            try {
                session.connect();
            } catch (JSchException ex) {
                ex.printStackTrace();
                error = true;
            }
        }
        
        if(!error){
            try {
                channel = (ChannelExec) session.openChannel("exec");
                ((ChannelExec) channel).setCommand(cmd);
                channel.connect();
                System.out.println("Channel connecté");
            } catch (JSchException ex) {
                ex.printStackTrace();
                error = true;
            }
        }
        
        if(error){
            this.sendErrorMessage("Problème de connexion", "Serveur " + session.getHost() + " indisponible.");
        }
        
        if(channel == null){
            System.err.print("CommandFailException");
            throw new CommandFailException(cmd);
        }
        
        System.out.println("on retourne une commande = " + channel);
        return channel;
    }
    
    public boolean DHCPHasChanged(String ip, String user, String pwd){
        if(!ip.equals(this.dhcpIP) || !user.equals(this.dhcpUser) || !pwd.equals(this.dhcpPwd) || this.sessionDHCP == null){
            try {
                this.sessionDHCP = SSH.createSession(ip,user,pwd);
            } catch (JSchException ex) {}
            return true;
        }
        return false;
    }
    
    public boolean FireWallHasChanged(String ip, String user, String pwd){
        if(!ip.equals(this.fwIP) || !user.equals(this.fwUser) || !pwd.equals(this.fwPwd) || this.sessionFireWall == null){
            try {
                this.sessionFireWall = SSH.createSession(ip,user,pwd);
            } catch (JSchException ex) {}
            return true;
        }
        return false;
    }
    
    public boolean LogsHasChanged(String ip, String user, String pwd){
        System.out.println("test " + ip + " et " + this.logsIP);
        if(!ip.equals(this.logsIP) || !user.equals(this.logsUser) || !pwd.equals(this.logsPwd) || this.sessionLogs == null){
            try {
                this.sessionLogs = SSH.createSession(ip,user,pwd);
            } catch (JSchException ex) {}
            return true;
        }
        return false;
    }

    public SSHStatus getStatusLogs() {
        return statusLogs;
    }

    public SSHStatus getStatusDHCP() {        
        return statusDHCP;
    }

    public SSHStatus getStatusFireWall() {
        return statusFW;
    }

    public Session getSessionLogs() {
        return sessionLogs;
    }

    public Session getSessionDHCP() {
        return sessionDHCP;
    }

    public Session getSessionFireWall() {
        return sessionFireWall;
    }
}
